using System;
namespace ch.ethz.ssh2.crypto.digest
{
	
	/// <summary> HMAC.
	/// 
	/// </summary>
	/// <author>  Christian Plattner
	/// </author>
	/// <version>  2.50, 03/15/10
	/// </version>
	public sealed class HMAC : Digest
	{
		public int DigestLength
		{
			get
			{
				return size;
			}
			
		}
		internal Digest md;
		internal byte[] k_xor_ipad;
		internal byte[] k_xor_opad;
		
		internal byte[] tmp;
		
		internal int size;
		
		public HMAC(Digest md, byte[] key, int size)
		{
			this.md = md;
			this.size = size;
			
			tmp = new byte[md.DigestLength];
			
			//UPGRADE_NOTE: Final was removed from the declaration of 'BLOCKSIZE '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
			int BLOCKSIZE = 64;
			
			k_xor_ipad = new byte[BLOCKSIZE];
			k_xor_opad = new byte[BLOCKSIZE];
			
			if (key.Length > BLOCKSIZE)
			{
				md.reset();
				md.update(key);
				md.digest(tmp);
				key = tmp;
			}
			
			Array.Copy(key, 0, k_xor_ipad, 0, key.Length);
			Array.Copy(key, 0, k_xor_opad, 0, key.Length);
			
			for (int i = 0; i < BLOCKSIZE; i++)
			{
				k_xor_ipad[i] ^= (byte) (0x36);
				k_xor_opad[i] ^= (byte) (0x5C);
			}
			md.update(k_xor_ipad);
		}
		
		public void  update(byte b)
		{
			md.update(b);
		}
		
		public void  update(byte[] b)
		{
			md.update(b);
		}
		
		public void  update(byte[] b, int off, int len)
		{
			md.update(b, off, len);
		}
		
		public void  reset()
		{
			md.reset();
			md.update(k_xor_ipad);
		}
		
		public void  digest(byte[] output)
		{
			digest(output, 0);
		}
		
		public void  digest(byte[] output, int off)
		{
			md.digest(tmp);
			
			md.update(k_xor_opad);
			md.update(tmp);
			
			md.digest(tmp);
			
			Array.Copy(tmp, 0, output, off, size);
			
			md.update(k_xor_ipad);
		}
	}
}